home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / share / cvs / contrib / log_accum < prev    next >
Text File  |  2005-10-16  |  23KB  |  780 lines

  1. #! /usr/bin/perl -T
  2. # -*-Perl-*-
  3.  
  4. ###############################################################################
  5. ###############################################################################
  6. ###############################################################################
  7. #
  8. # THIS SCRIPT IS PROBABLY BROKEN.  REMOVING THE -T SWITCH ON THE #! LINE ABOVE
  9. # WOULD FIX IT, BUT THIS IS INSECURE.  WE RECOMMEND FIXING THE ERRORS WHICH THE
  10. # -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
  11. # SERVER TRIGGER.  PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
  12. # NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
  13. # <bug-cvs@gnu.org> MAILING LIST.
  14. #
  15. # For more on general Perl security and taint-checking, please try running the
  16. # `perldoc perlsec' command.
  17. #
  18. ###############################################################################
  19. ###############################################################################
  20. ###############################################################################
  21.  
  22. # Perl filter to handle the log messages from the checkin of files in
  23. # a directory.  This script will group the lists of files by log
  24. # message, and mail a single consolidated log message at the end of
  25. # the commit.
  26. #
  27. # This file assumes a pre-commit checking program that leaves the
  28. # names of the first and last commit directories in a temporary file.
  29. #
  30. # IMPORTANT: what the above means is, this script interacts with
  31. # commit_prep, in that they have to agree on the tmpfile name to use.
  32. # See $LAST_FILE below. 
  33. #
  34. # How this works: CVS triggers this script once for each directory
  35. # involved in the commit -- in other words, a single commit can invoke
  36. # this script N times.  It knows when it's on the last invocation by
  37. # examining the contents of $LAST_FILE.  Between invocations, it
  38. # caches information for its future incarnations in various temporary
  39. # files in /tmp, which are named according to the process group and
  40. # the committer (by themselves, neither of these are unique, but
  41. # together they almost always are, unless the same user is doing two
  42. # commits simultaneously).  The final invocation is the one that
  43. # actually sends the mail -- it gathers up the cached information,
  44. # combines that with what it found out on this pass, and sends a
  45. # commit message to the appropriate mailing list.
  46. #
  47. # (Ask Karl Fogel <kfogel@collab.net> if questions.)
  48. #
  49. # Contributed by David Hampton <hampton@cisco.com>
  50. # Roy Fielding removed useless code and added log/mail of new files
  51. # Ken Coar added special processing (i.e., no diffs) for binary files
  52. #
  53.  
  54. ############################################################
  55. #
  56. # Configurable options
  57. #
  58. ############################################################
  59. #
  60. # The newest versions of CVS have UseNewInfoFmtStrings=yes
  61. # to change the arguments being passed on the command line.
  62. # If you are using %1s on the command line, then set this
  63. # value to 0.
  64. # 0 = old-style %1s format. use split(' ') to separate ARGV into filesnames.
  65. # 1 = new-style %s format. Note: allows spaces in filenames.
  66. my $UseNewInfoFmtStrings = 0;
  67.  
  68. #
  69. # Where do you want the RCS ID and delta info?
  70. # 0 = none,
  71. # 1 = in mail only,
  72. # 2 = in both mail and logs.
  73. #
  74. $rcsidinfo = 2;
  75.  
  76. #if you are using CVS web then set this to some value... if not set it to ""
  77. #
  78. # When set properly, this will cause links to aspects of the project to
  79. # print in the commit emails.
  80. #$CVSWEB_SCHEME = "http";
  81. #$CVSWEB_DOMAIN = "cvshome.org";
  82. #$CVSWEB_PORT = "80";
  83. #$CVSWEB_URI = "source/browse/";
  84. #$SEND_URL = "true";
  85. $SEND_DIFF = "true";
  86.  
  87.  
  88. # Set this to a domain to have CVS pretend that all users who make
  89. # commits have mail accounts within that domain.
  90. #$EMULATE_LOCAL_MAIL_USER="cvshome.org"; 
  91.  
  92. # Set this to '-c' for context diffs; defaults to '-u' for unidiff format.
  93. $difftype = '-uN';
  94.  
  95. ############################################################
  96. #
  97. # Constants
  98. #
  99. ############################################################
  100. $STATE_NONE    = 0;
  101. $STATE_CHANGED = 1;
  102. $STATE_ADDED   = 2;
  103. $STATE_REMOVED = 3;
  104. $STATE_LOG     = 4;
  105.  
  106. $TMPDIR        = $ENV{'TMPDIR'} || '/tmp';
  107. $FILE_PREFIX   = '#cvs.';
  108.  
  109. $LAST_FILE     = "$TMPDIR/${FILE_PREFIX}lastdir";  # Created by commit_prep!
  110. $ADDED_FILE    = "$TMPDIR/${FILE_PREFIX}files.added";
  111. $REMOVED_FILE  = "$TMPDIR/${FILE_PREFIX}files.removed";
  112. $LOG_FILE      = "$TMPDIR/${FILE_PREFIX}files.log";
  113. $BRANCH_FILE   = "$TMPDIR/${FILE_PREFIX}files.branch";
  114. $MLIST_FILE    = "$TMPDIR/${FILE_PREFIX}files.mlist";
  115. $SUMMARY_FILE  = "$TMPDIR/${FILE_PREFIX}files.summary";
  116.  
  117. $CVSROOT       = $ENV{'CVSROOT'};
  118.  
  119. $MAIL_CMD      = "| /usr/lib/sendmail -i -t";
  120. #$MAIL_CMD      = "| /var/qmail/bin/qmail-inject";
  121. $MAIL_FROM     = 'commitlogger';  #not needed if EMULATE_LOCAL_MAIL_USER
  122. $SUBJECT_PRE   = 'CVS update:';
  123.  
  124.  
  125. ############################################################
  126. #
  127. # Subroutines
  128. #
  129. ############################################################
  130.  
  131. sub format_names {
  132.     local($dir, @files) = @_;
  133.     local(@lines);
  134.  
  135.     $lines[0] = sprintf(" %-08s", $dir);
  136.     foreach $file (@files) {
  137.         if (length($lines[$#lines]) + length($file) > 60) {
  138.             $lines[++$#lines] = sprintf(" %8s", " ");
  139.         }
  140.         $lines[$#lines] .= " ".$file;
  141.     }
  142.     @lines;
  143. }
  144.  
  145. sub cleanup_tmpfiles {
  146.     local(@files);
  147.  
  148.     opendir(DIR, $TMPDIR);
  149.     push(@files, grep(/^${FILE_PREFIX}.*\.${id}\.${cvs_user}$/, readdir(DIR)));
  150.     closedir(DIR);
  151.     foreach (@files) {
  152.         unlink "$TMPDIR/$_";
  153.     }
  154. }
  155.  
  156. sub write_logfile {
  157.     local($filename, @lines) = @_;
  158.  
  159.     open(FILE, ">$filename") || die ("Cannot open log file $filename: $!\n");
  160.     print(FILE join("\n", @lines), "\n");
  161.     close(FILE);
  162. }
  163.  
  164. sub append_to_file {
  165.     local($filename, $dir, @files) = @_;
  166.  
  167.     if (@files) {
  168.         local(@lines) = &format_names($dir, @files);
  169.         open(FILE, ">>$filename") || die ("Cannot open file $filename: $!\n");
  170.         print(FILE join("\n", @lines), "\n");
  171.         close(FILE);
  172.     }
  173. }
  174.  
  175. sub write_line {
  176.     local($filename, $line) = @_;
  177.  
  178.     open(FILE, ">$filename") || die("Cannot open file $filename: $!\n");
  179.     print(FILE $line, "\n");
  180.     close(FILE);
  181. }
  182.  
  183. sub append_line {
  184.     local($filename, $line) = @_;
  185.  
  186.     open(FILE, ">>$filename") || die("Cannot open file $filename: $!\n");
  187.     print(FILE $line, "\n");
  188.     close(FILE);
  189. }
  190.  
  191. sub read_line {
  192.     local($filename) = @_;
  193.     local($line);
  194.  
  195.     open(FILE, "<$filename") || die("Cannot open file $filename: $!\n");
  196.     $line = <FILE>;
  197.     close(FILE);
  198.     chomp($line);
  199.     $line;
  200. }
  201.  
  202. sub read_line_nodie {
  203.     local($filename) = @_;
  204.     local($line);
  205.     open(FILE, "<$filename") || return ("");
  206.  
  207.     $line = <FILE>;
  208.     close(FILE);
  209.     chomp($line);
  210.     $line;
  211. }
  212.  
  213. sub read_file_lines {
  214.     local($filename) = @_;
  215.     local(@text) = ();
  216.  
  217.     open(FILE, "<$filename") || return ();
  218.     while (<FILE>) {
  219.         chomp;
  220.         push(@text, $_);
  221.     }
  222.     close(FILE);
  223.     @text;
  224. }
  225.  
  226. sub read_file {
  227.     local($filename, $leader) = @_;
  228.     local(@text) = ();
  229.  
  230.     open(FILE, "<$filename") || return ();
  231.     while (<FILE>) {
  232.         chomp;
  233.         push(@text, sprintf("  %-10s  %s", $leader, $_));
  234.         $leader = "";
  235.     }
  236.     close(FILE);
  237.     @text;
  238. }
  239.  
  240. sub read_logfile {
  241.     local($filename, $leader) = @_;
  242.     local(@text) = ();
  243.  
  244.     open(FILE, "<$filename") || die ("Cannot open log file $filename: $!\n");
  245.     while (<FILE>) {
  246.         chomp;
  247.         push(@text, $leader.$_);
  248.     }
  249.     close(FILE);
  250.     @text;
  251. }
  252.  
  253. #
  254. # do an 'cvs -Qn status' on each file in the arguments, and extract info.
  255. #
  256. sub change_summary {
  257.     local($out, @filenames) = @_;
  258.     local(@revline);
  259.     local($file, $rev, $rcsfile, $line, $vhost, $cvsweb_base);
  260.  
  261.     while (@filenames) {
  262.         $file = shift @filenames;
  263.  
  264.         if ("$file" eq "") {
  265.             next;
  266.         }
  267.  
  268.         open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'status', '--', $file;
  269.  
  270.         $rev = "";
  271.         $delta = "";
  272.         $rcsfile = "";
  273.  
  274.  
  275.         while (<RCS>) {
  276.             if (/^[ \t]*Repository revision/) {
  277.                 chomp;
  278.                 @revline = split(' ', $_);
  279.                 $rev = $revline[2];
  280.                 $rcsfile = $revline[3];
  281.                 $rcsfile =~ s,^$CVSROOT/,,;
  282.                 $rcsfile =~ s/,v$//;
  283.             }
  284.         }
  285.         close(RCS);
  286.  
  287.  
  288.         if ($rev ne '' && $rcsfile ne '') {
  289.             open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'log', "-r$rev",
  290.                     '--', $file;
  291.             while (<RCS>) {
  292.                 if (/^date:/) {
  293.                     chomp;
  294.                     $delta = $_;
  295.                     $delta =~ s/^.*;//;
  296.                     $delta =~ s/^[\s]+lines://;
  297.                 }
  298.             }
  299.             close(RCS);
  300.         }
  301.  
  302.         $diff = "\n\n";
  303.         $vhost = $path[0];
  304.         if ($CVSWEB_PORT eq "80") {
  305.           $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN/$CVSWEB_URI";
  306.         }
  307.         else {
  308.           $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN:$CVSWEB_PORT/$CVSWEB_URI";
  309.         }
  310.         if ($SEND_URL eq "true") {
  311.           $diff .= $cvsweb_base . join("/", @path) . "/$file";
  312.         }
  313.  
  314.         #
  315.         # If this is a binary file, don't try to report a diff; not only is
  316.         # it meaningless, but it also screws up some mailers.  We rely on
  317.         # Perl's 'is this binary' algorithm; it's pretty good.  But not
  318.         # perfect.
  319.         #
  320.         if (($file =~ /\.(?:pdf|gif|jpg|mpg)$/i) || (-B $file)) {
  321.           if ($SEND_URL eq "true") {
  322.             $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n";
  323.           }
  324.           if ($SEND_DIFF eq "true") {
  325.             $diff .= "\t<<Binary file>>\n\n";
  326.           }
  327.         }
  328.         else {
  329.             #
  330.             # Get the differences between this and the previous revision,
  331.             # being aware that new files always have revision '1.1' and
  332.             # new branches always end in '.n.1'.
  333.             #
  334.             if ($rev =~ /^(.*)\.([0-9]+)$/) {
  335.                 $prev = $2 - 1;
  336.                 $prev_rev = $1 . '.' .  $prev;
  337.  
  338.                 $prev_rev =~ s/\.[0-9]+\.0$//;# Truncate if first rev on branch
  339.  
  340.                 if ($rev eq '1.1') {
  341.                   if ($SEND_URL eq "true") {
  342.                     $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n";
  343.                   }
  344.                   if ($SEND_DIFF eq "true") {
  345.                     open(DIFF, "-|")
  346.                       || exec "$cvsbin/cvs", '-Qn', 'update', '-p', '-r1.1',
  347.                   '--', $file;
  348.                     $diff .= "Index: $file\n=================================="
  349.                       . "=================================\n";
  350.                   }
  351.                 }
  352.                 else {
  353.                   if ($SEND_URL eq "true") {
  354.                     $diff .= ".diff?r1=$prev_rev&r2=$rev\n\n";
  355.                   }
  356.                   if ($SEND_DIFF eq "true") {
  357.                     $diff .= "(In the diff below, changes in quantity "
  358.                       . "of whitespace are not shown.)\n\n";
  359.                     open(DIFF, "-|")
  360.                       || exec "$cvsbin/cvs", '-Qn', 'diff', "$difftype",
  361.                       '-b', "-r$prev_rev", "-r$rev", '--', $file;
  362.                   }
  363.                 }
  364.  
  365.                 if ($SEND_DIFF eq "true") {
  366.                   while (<DIFF>) {
  367.                     $diff .= $_;
  368.                   }
  369.                   close(DIFF);
  370.                 }
  371.                 $diff .= "\n\n";
  372.             }
  373.         }
  374.  
  375.         &append_line($out, sprintf("%-9s%-12s%s%s", $rev, $delta,
  376.                                    $rcsfile, $diff));
  377.     }
  378. }
  379.  
  380.  
  381. sub build_header {
  382.     local($header);
  383.     delete $ENV{'TZ'};
  384.     local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
  385.  
  386.     $header = sprintf("  User: %-8s\n  Date: %02d/%02d/%02d %02d:%02d:%02d",
  387.                        $cvs_user, $year%100, $mon+1, $mday,
  388.                        $hour, $min, $sec);
  389. #    $header = sprintf("%-8s    %02d/%02d/%02d %02d:%02d:%02d",
  390. #                       $login, $year%100, $mon+1, $mday,
  391. #                       $hour, $min, $sec);
  392. }
  393.  
  394. # !!! Destination Mailing-list and history file mappings here !!!
  395.  
  396. #sub mlist_map
  397. #{
  398. #    local($path) = @_;
  399. #    my $domain = "cvshome.org";
  400. #    
  401. #    if ($path =~ /^([^\/]+)/) {
  402. #        return "cvs\@$1.$domain";
  403. #    } else {
  404. #        return "cvs\@$domain";
  405. #    }
  406. #}    
  407.  
  408. sub derive_subject_from_changes_file ()
  409. {
  410.   my $subj = "";
  411.  
  412.   for ($i = 0; ; $i++)
  413.   {
  414.     open (CH, "<$CHANGED_FILE.$i.$id.$cvs_user") or last;
  415.  
  416.     while (my $change = <CH>)
  417.     {
  418.       # A changes file looks like this:
  419.       #
  420.       #  src      foo.c newfile.html
  421.       #  www      index.html project_nav.html
  422.       #
  423.       # Each line is " Dir File1 File2 ..."
  424.       # We only care about Dir, since the subject line should
  425.       # summarize. 
  426.       
  427.       $change =~ s/^[ \t]*//;
  428.       $change =~ /^([^ \t]+)[ \t]*/;
  429.       my $dir = $1;
  430.       # Fold to rightmost directory component
  431.       $dir =~ /([^\/]+)$/;
  432.       $dir = $1;
  433.       if ($subj eq "") {
  434.         $subj = $dir;
  435.       } else {
  436.         $subj .= ", $dir"; 
  437.       }
  438.     }
  439.     close (CH);
  440.   }
  441.  
  442.   if ($subj ne "") {
  443.       $subj = "MODIFIED: $subj ..."; 
  444.   }
  445.   else {
  446.       # NPM: See if there's any file-addition notifications.
  447.       my $added = &read_line_nodie("$ADDED_FILE.$i.$id.$cvs_user");
  448.       if ($added ne "") {
  449.           $subj .= "ADDED: $added "; 
  450.       }
  451.     
  452. #    print "derive_subject_from_changes_file().. added== $added \n";
  453.     
  454.        ## NPM: See if there's any file-removal notications.
  455.       my $removed = &read_line_nodie("$REMOVED_FILE.$i.$id.$cvs_user");
  456.       if ($removed ne "") {
  457.           $subj .= "REMOVED: $removed "; 
  458.       }
  459.     
  460. #    print "derive_subject_from_changes_file().. removed== $removed \n";
  461.     
  462.       ## NPM: See if there's any branch notifications.
  463.       my $branched = &read_line_nodie("$BRANCH_FILE.$i.$id.$cvs_user");
  464.       if ($branched ne "") {
  465.           $subj .= "BRANCHED: $branched"; 
  466.       }
  467.     
  468. #    print "derive_subject_from_changes_file().. branched== $branched \n";
  469.     
  470.       ## NPM: DEFAULT: DIRECTORY CREATION (c.f. "Check for a new directory first" in main mody)
  471.       if ($subj eq "") {
  472.           my $subject = join("/", @path);
  473.           $subj = "NEW: $subject"; 
  474.       }    
  475.   }
  476.  
  477.   return $subj;
  478. }
  479.  
  480. sub mail_notification
  481. {
  482.     local($addr_list, @text) = @_;
  483.     local($mail_to);
  484.  
  485.     my $subj = &derive_subject_from_changes_file ();
  486.  
  487.     if ($EMULATE_LOCAL_MAIL_USER ne "") {
  488.         $MAIL_FROM = "$cvs_user\@$EMULATE_LOCAL_MAIL_USER";
  489.     }
  490.  
  491.     $mail_to = join(", ", @{$addr_list});
  492.  
  493.     print "Mailing the commit message to $mail_to (from $MAIL_FROM)\n";
  494.  
  495.     $ENV{'MAILUSER'} = $MAIL_FROM;
  496.     # Commented out on hocus, so comment it out here.  -kff
  497.     # $ENV{'QMAILINJECT'} = 'f';
  498.  
  499.     open(MAIL, "$MAIL_CMD -f$MAIL_FROM");
  500.     print MAIL "From: $MAIL_FROM\n";
  501.     print MAIL "To: $mail_to\n";
  502.     print MAIL "Subject: $SUBJECT_PRE $subj\n\n";
  503.     print(MAIL join("\n", @text));
  504.     close(MAIL);
  505. #    print "Mailing the commit message to $MAIL_TO...\n";
  506. #
  507. #    #added by jrobbins@collab.net 1999/12/15
  508. #    # attempt to get rid of anonymous
  509. #    $ENV{'MAILUSER'} = 'commitlogger';
  510. #    $ENV{'QMAILINJECT'} = 'f';
  511. #
  512. #    open(MAIL, "| /var/qmail/bin/qmail-inject");
  513. #    print(MAIL "To: $MAIL_TO\n"); 
  514. #    print(MAIL "Subject: cvs commit: $ARGV[0]\n"); 
  515. #    print(MAIL join("\n", @text));
  516. #    close(MAIL);
  517. }
  518.  
  519. ## process the command line arguments sent to this script
  520. ## it returns an array of files, %s, sent from the loginfo
  521. ## command
  522. sub process_argv
  523. {
  524.     local(@argv) = @_;
  525.     local(@files);
  526.     local($arg);
  527.     print "Processing log script arguments...\n";
  528.  
  529.     if ($UseNewInfoFmtStrings) {
  530.         while (@argv) {
  531.             $arg = shift @argv;
  532.  
  533.             if ($arg eq '-u' && !defined($cvs_user)) {
  534.                 $cvs_user = shift @argv;
  535.             }
  536.             if ($arg eq '- New directory') {
  537.                 $new_directory = 1;
  538.             } elsif ($arg eq '- Imported sources') {
  539.                 $imported_sources = 1;
  540.             } else {
  541.                 push(@files, $arg);
  542.             }
  543.         }
  544.     } else {
  545.         while (@argv) {
  546.             $arg = shift @argv;
  547.  
  548.             if ($arg eq '-u') {
  549.                 $cvs_user = shift @argv;
  550.             } else {
  551.                 ($donefiles) && die "Too many arguments!\n";
  552.                 $donefiles = 1;
  553.                 $ARGV[0] = $arg;
  554.                 if ($arg =~ s/ - New directory//) {
  555.                     $new_directory = 1;
  556.                 } elsif ($arg =~ s/ - Imported sources//) {
  557.                     $imported_sources = 1;
  558.                 }
  559.                 @files = split(' ', $arg);
  560.             }
  561.         }
  562.     }
  563.     return @files;
  564. }
  565.  
  566.  
  567. #############################################################
  568. #
  569. # Main Body
  570. #
  571. ############################################################
  572. #
  573. # Setup environment
  574. #
  575. umask (002);
  576.  
  577. # Connect to the database
  578. $cvsbin = "/usr/bin";
  579.  
  580. #
  581. # Initialize basic variables
  582. #
  583. $id = getpgrp();
  584. $state = $STATE_NONE;
  585. $cvs_user = $ENV{'USER'} || getlogin || (getpwuid($<))[0] || sprintf("uid#%d",$<);
  586. $new_directory = 0;             # Is this a 'cvs add directory' command?
  587. $imported_sources = 0;          # Is this a 'cvs import' command?
  588. @files = process_argv(@ARGV);
  589. @path = split('/', $files[0]);
  590. if ($#path == 0) {
  591.     $dir = ".";
  592. } else {
  593.     $dir = join('/', @path[1..$#path]);
  594. }
  595. #print("ARGV  - ", join(":", @ARGV), "\n");
  596. #print("files - ", join(":", @files), "\n");
  597. #print("path  - ", join(":", @path), "\n");
  598. #print("dir   - ", $dir, "\n");
  599. #print("id    - ", $id, "\n");
  600.  
  601. #
  602. # Map the repository directory to an email address for commitlogs to be sent
  603. # to.
  604. #
  605. #$mlist = &mlist_map($files[0]);
  606.  
  607. ##########################
  608. #
  609. # Check for a new directory first.  This will always appear as a
  610. # single item in the argument list, and an empty log message.
  611. #
  612. if ($new_directory) {
  613.     $header = &build_header;
  614.     @text = ();
  615.     push(@text, $header);
  616.     push(@text, "");
  617.     push(@text, "  ".$files[0]." - New directory");
  618.     &mail_notification([ $mlist ], @text);
  619.     exit 0;
  620. }
  621.  
  622. #
  623. # Iterate over the body of the message collecting information.
  624. #
  625. while (<STDIN>) {
  626.     chomp;                      # Drop the newline
  627.     if (/^Revision\/Branch:/) {
  628.         s,^Revision/Branch:,,;
  629.         push (@branch_lines, split);
  630.         next;
  631.     }
  632. #    next if (/^[ \t]+Tag:/ && $state != $STATE_LOG);
  633.     if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
  634.     if (/^Added Files/)    { $state = $STATE_ADDED;   next; }
  635.     if (/^Removed Files/)  { $state = $STATE_REMOVED; next; }
  636.     if (/^Log Message/)    { $state = $STATE_LOG;     last; }
  637.     s/[ \t\n]+$//;              # delete trailing space
  638.     
  639.     push (@changed_files, split) if ($state == $STATE_CHANGED);
  640.     push (@added_files,   split) if ($state == $STATE_ADDED);
  641.     push (@removed_files, split) if ($state == $STATE_REMOVED);
  642. }
  643. # Proces the /Log Message/ section now, if it exists.
  644. # Do this here rather than above to deal with Log messages
  645. # that include lines that confuse the state machine.
  646. if (!eof(STDIN)) {
  647.     while (<STDIN>) {
  648.         next unless ($state == $STATE_LOG); # eat all STDIN
  649.  
  650.         if ($state == $STATE_LOG) {
  651.             if (/^PR:$/i ||
  652.                 /^Reviewed by:$/i ||
  653.                 /^Submitted by:$/i ||
  654.                 /^Obtained from:$/i) {
  655.                 next;
  656.             }
  657.             push (@log_lines,     $_);
  658.         }
  659.     }
  660. }
  661.  
  662. #
  663. # Strip leading and trailing blank lines from the log message.  Also
  664. # compress multiple blank lines in the body of the message down to a
  665. # single blank line.
  666. # (Note, this only does the mail and changes log, not the rcs log).
  667. #
  668. while ($#log_lines > -1) {
  669.     last if ($log_lines[0] ne "");
  670.     shift(@log_lines);
  671. }
  672. while ($#log_lines > -1) {
  673.     last if ($log_lines[$#log_lines] ne "");
  674.     pop(@log_lines);
  675. }
  676. for ($i = $#log_lines; $i > 0; $i--) {
  677.     if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
  678.         splice(@log_lines, $i, 1);
  679.     }
  680. }
  681.  
  682. #
  683. # Find the log file that matches this log message
  684. #
  685. for ($i = 0; ; $i++) {
  686.     last if (! -e "$LOG_FILE.$i.$id.$cvs_user");
  687.     @text = &read_logfile("$LOG_FILE.$i.$id.$cvs_user", "");
  688.     last if ($#text == -1);
  689.     last if (join(" ", @log_lines) eq join(" ", @text));
  690. }
  691.  
  692. #
  693. # Spit out the information gathered in this pass.
  694. #
  695. &write_logfile("$LOG_FILE.$i.$id.$cvs_user", @log_lines);
  696. &append_to_file("$BRANCH_FILE.$i.$id.$cvs_user",  $dir, @branch_lines);
  697. &append_to_file("$ADDED_FILE.$i.$id.$cvs_user",   $dir, @added_files);
  698. &append_to_file("$CHANGED_FILE.$i.$id.$cvs_user", $dir, @changed_files);
  699. &append_to_file("$REMOVED_FILE.$i.$id.$cvs_user", $dir, @removed_files);
  700. &append_line("$MLIST_FILE.$i.$id.$cvs_user", $mlist);
  701. if ($rcsidinfo) {
  702.     &change_summary("$SUMMARY_FILE.$i.$id.$cvs_user", (@changed_files, @added_files));
  703. }
  704.  
  705. #
  706. # Check whether this is the last directory.  If not, quit.
  707. #
  708. if (-e "$LAST_FILE.$id.$cvs_user") {
  709.    $_ = &read_line("$LAST_FILE.$id.$cvs_user");
  710.    $tmpfiles = $files[0];
  711.    $tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g;
  712.    if (! grep(/$tmpfiles$/, $_)) {
  713.         print "More commits to come...\n";
  714.         exit 0
  715.    }
  716. }
  717.  
  718. #
  719. # This is it.  The commits are all finished.  Lump everything together
  720. # into a single message, fire a copy off to the mailing list, and drop
  721. # it on the end of the Changes file.
  722. #
  723. $header = &build_header;
  724.  
  725. #
  726. # Produce the final compilation of the log messages
  727. #
  728. @text = ();
  729. @mlist_list = ();
  730. push(@text, $header);
  731. push(@text, "");
  732. for ($i = 0; ; $i++) {
  733.     last if (! -e "$LOG_FILE.$i.$id.$cvs_user");
  734.     push(@text, &read_file("$BRANCH_FILE.$i.$id.$cvs_user", "Branch:"));
  735.     push(@text, &read_file("$CHANGED_FILE.$i.$id.$cvs_user", "Modified:"));
  736.     push(@text, &read_file("$ADDED_FILE.$i.$id.$cvs_user", "Added:"));
  737.     push(@text, &read_file("$REMOVED_FILE.$i.$id.$cvs_user", "Removed:"));
  738.     push(@text, "  Log:");
  739.     push(@text, &read_logfile("$LOG_FILE.$i.$id.$cvs_user", "  "));
  740.     push(@mlist_list, &read_file_lines("$MLIST_FILE.$i.$id.$cvs_user"));
  741.     if ($rcsidinfo == 2) {
  742.         if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") {
  743.             push(@text, "  ");
  744.             push(@text, "  Revision  Changes    Path");
  745.             push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", "  "));
  746.         }
  747.     }
  748.     push(@text, "");
  749. }
  750.  
  751. #
  752. # Now generate the extra info for the mail message..
  753. #
  754. if ($rcsidinfo == 1) {
  755.     $revhdr = 0;
  756.     for ($i = 0; ; $i++) {
  757.         last if (! -e "$LOG_FILE.$i.$id.$cvs_user");
  758.         if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") {
  759.             if (!$revhdr++) {
  760.                 push(@text, "Revision  Changes    Path");
  761.             }
  762.             push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", ""));
  763.         }
  764.     }
  765.     if ($revhdr) {
  766.         push(@text, "");        # consistancy...
  767.     }
  768. }
  769.  
  770. %mlist_hash = ();
  771.  
  772. foreach (@mlist_list) { $mlist_hash{ $_ } = 1; }
  773.  
  774. #
  775. # Mail out the notification.
  776. #
  777. &mail_notification([ keys(%mlist_hash) ], @text);
  778. &cleanup_tmpfiles;
  779. exit 0;
  780.